import React, { useEffect, useLayoutEffect, useMemo, useState } from 'react';
import PropTypes from 'prop-types';
import { filterTreeData, tree2array } from '@/utils/tree';
import { Empty, Tree, Input, Select } from 'antd';
import { debounce, difference, flatten, intersection } from 'lodash';
import { HighlightText } from '@/molecules';
import { useControllableValue } from '@/hooks';
import IconFont from '@/components/IconFont';
import styles from './index.less';

const checkEnableTreeItem = (node, isLeaf) => {
    if (node.disabled) {
        return false;
    }
    if (isLeaf) {
        return true;
    }
    let result = false;
    if (node.children) {
        for (let i = 0; i < node.children.length; i += 1) {
            if (checkEnableTreeItem(node.children[i])) {
                result = true;
                break;
            }
        }
    }
    if (node.leaves?.filter(item => !item.disabled).length) {
        result = true;
    }
    return result;
};

// 人员选择器
const EmployeeSelector = props => {
    const { treeData = [] } = props;
    const arrayData = useMemo(() => tree2array(treeData), [treeData]);
    const leavesDataMap = useMemo(() => {
        const arr = flatten(arrayData.map(item => item.leaves || []));
        return arr.reduce((total, item) => ({ ...total, [item.id]: item }), {});
    }, [arrayData]);
    const [value = [], onChange] = useControllableValue(props);
    const [keyword, setKeyword] = useState();
    const [searchType, setSearchType] = useState('name');
    const setKeywordDebounce = useMemo(() => debounce(setKeyword, 500), []);
    // 过滤后的树数据
    const filteredTreeData = useMemo(() => {
        if (keyword) {
            if (searchType === 'name') {
                return filterTreeData(
                    treeData,
                    item => !keyword || item?.leaves?.some(leaf => leaf.name.includes(keyword))
                );
            }
            return filterTreeData(treeData, item => !keyword || item?.name?.includes(keyword));
        }
        return treeData;
    }, [keyword, searchType, treeData]);
    const filteredArrayData = useMemo(() => tree2array(filteredTreeData), [filteredTreeData]);
    const [expandedKeys, setExpandedKeys] = useState([]);

    useEffect(() => {
        if (keyword) {
            setExpandedKeys(filteredArrayData.map(item => item.id));
        }
    }, [filteredArrayData, filteredTreeData, keyword]);

    // 动态计算展开的节点
    useEffect(() => {
        if (keyword) {
            const result = [];
            const pickPid = array => {
                array.forEach(item => {
                    if (item.children?.length || (searchType === 'name' ? item.leaves?.length : !item.leaves?.length)) {
                        result.push(item.id);
                    }
                    if (item.children?.length) {
                        pickPid(item.children || []);
                    }
                });
            };
            pickPid(filteredTreeData);
            setExpandedKeys(result);
        }
    }, [filteredTreeData, keyword, searchType]);

    // 第一个节点不允许被折叠
    useLayoutEffect(() => {
        if (filteredTreeData?.length && !expandedKeys.includes(filteredTreeData[0]?.id)) {
            setExpandedKeys([filteredTreeData[0].id, ...expandedKeys]);
        }
    }, [expandedKeys, filteredTreeData]);

    // 当前选项被过滤后的树选中的值
    const currentTreeCheckedValue = intersection(
        value,
        flatten(filteredArrayData.map(item => item.leaves || [])).map(item => item.id)
    );

    const handleSearchChange = e => {
        setKeywordDebounce(e?.target?.value);
    };

    const handleSearchTypeChange = val => {
        setSearchType(val);
        setKeyword(keyword);
    };

    // 树节点选择事件
    // 解决因为特殊情况下(子节点没有有效子节点)导致半选复选框无法取消选择的问题
    const handleTreeCheck = (keys, target) => {
        let currentKeys = [...keys];
        // const { halfChecked } = target.node.props; // 当前节点是否是半选状态
        const filteredTreeDataLeaves = flatten(filteredArrayData.map(item => item.leaves || []));
        // 从旧的值当中删除当前所有选项的数据, 先删除, 再添加
        const oldValue = value.filter(
            item => !filteredArrayData.concat(filteredTreeDataLeaves).some(m => m.id === item)
        );
        const getChildrenTreeItemId = (nodes = []) => {
            let result = [];
            for (let i = 0; i < nodes.length; i += 1) {
                result.push(nodes[i].key);
                if (nodes[i].props.children?.length) {
                    result = result.concat(getChildrenTreeItemId(nodes[i].props.children));
                }
            }
            return result;
        };
        const getValue = () => [
            ...new Set([
                ...oldValue,
                ...difference(
                    currentKeys,
                    arrayData.map(item => item.id)
                )
            ])
        ];

        let result = getValue();
        if (result.length === value.length) {
            currentKeys = difference(result, getChildrenTreeItemId(target.node.props?.children));
            result = getValue();
        }

        if (onChange) {
            onChange(result);
        }
    };

    const handleTreeExpand = keys => {
        setExpandedKeys(keys);
    };

    // 渲染树节点
    const renderTreeNode = (nodes, isLeaf = false) =>
        nodes?.map(node => {
            const highlightText = (
                <>
                    {isLeaf && node?.leaderPositionFlag === 1 ? (
                        <span style={{ marginLeft: -3, color: 'rgba(0, 0, 0, 0.65)' }}>
                            <IconFont icon="iconLeaderMark" className={styles.leaderIcon} />
                            <HighlightText keywords={keyword}>{node.name}</HighlightText>
                        </span>
                    ) : (
                        <HighlightText keywords={keyword}>{node.name}</HighlightText>
                    )}
                    {isLeaf && node.dutyAlias ? <span style={{ color: '#999' }}> - {node.dutyAlias}</span> : null}
                </>
            );
            const title = !isLeaf && node.disabled ? `${node.name}(审批中)` : highlightText;
            return (
                <Tree.TreeNode
                    key={node.id}
                    title={title}
                    disabled={!checkEnableTreeItem(node, isLeaf)}
                    checkable={node?.leaderPositionFlag !== 1}
                    selectable={node.selectable ?? true}
                    isLeaf={isLeaf || (!node.children?.length && !node.leaves?.length) || node.disabled}
                >
                    {[
                        ...(!isLeaf && node.disabled
                            ? []
                            : renderTreeNode(
                                  searchType === 'name' && keyword
                                      ? node?.leaves?.filter(leaf => leaf.name.includes(keyword)) || []
                                      : node?.leaves || [],
                                  true
                              )),
                        ...renderTreeNode(node.children || [])
                    ]}
                </Tree.TreeNode>
            );
        });

    // 删除已选节点
    const handleRemoveCheckedItem = currentValue => {
        if (onChange) {
            onChange(value.filter(key => key !== currentValue));
        }
    };

    return (
        <div className={styles.employeeSelector}>
            <div className={styles.treeContainer}>
                <Input.Group compact className={styles.treeSelectSearch}>
                    <Select
                        value={searchType}
                        onChange={handleSearchTypeChange}
                        className={styles.treeSelectSearchType}
                    >
                        <Select.Option value="name">姓名</Select.Option>
                        <Select.Option value="organizations">机构</Select.Option>
                    </Select>
                    <Input
                        className={styles.treeSelectSearchInput}
                        placeholder="搜索"
                        suffix={
                            <IconFont
                                icon="iconoa_top_bnt_search_normal"
                                style={{ fontSize: 16, color: 'rgba(0,0,0,0.45)' }}
                            />
                        }
                        allowClear
                        onChange={handleSearchChange}
                    />
                </Input.Group>
                {filteredTreeData?.length ? (
                    <div className={styles.treeMain}>
                        <Tree
                            onExpand={handleTreeExpand}
                            expandedKeys={expandedKeys}
                            checkable
                            checkStrictly={false}
                            checkedKeys={currentTreeCheckedValue}
                            selectable={false}
                            onCheck={handleTreeCheck}
                        >
                            {renderTreeNode(filteredTreeData)}
                        </Tree>
                    </div>
                ) : (
                    <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
                )}
            </div>
            <div className={styles.previewContainer}>
                <div className={styles.checkedTotal}>已选: {value.length}</div>
                <div className={styles.checkedList}>
                    {value?.map(id => (
                        <div key={id} className={styles.checkedItem}>
                            <div className={styles.checkedItemTitle}>
                                {leavesDataMap[id]?.name}
                                <span> - {leavesDataMap[id]?.dutyAlias}</span>
                            </div>
                            <IconFont
                                className={styles.checkedItemTitleClose}
                                icon="iconclose_o"
                                style={{ fontSize: 18 }}
                                onClick={() => handleRemoveCheckedItem(id)}
                            />
                        </div>
                    ))}
                </div>
            </div>
        </div>
    );
};

EmployeeSelector.propTypes = {
    treeData: PropTypes.array.isRequired
};

EmployeeSelector.displayName = 'EmployeeSelector';

export default EmployeeSelector;
